package controllers.api;

import ext.wxcp.WeixinCpHelper;
import ext.wxcp.WxCpContext;
import ext.wxcp.WxCpInvocation;
import models.enums.WxcpAppType;
import me.chanjar.weixin.cp.api.WxCpConfigStorage;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpXmlMessage;
import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage;
import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil;
import me.chanjar.weixin.cp.util.xml.XStreamTransformer;
import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.MDC;
import play.Logger;
import play.libs.IO;
import play.mvc.Controller;
import util.common.RandomNumberUtil;
import util.extension.DefaultAction;
import util.extension.ExtensionInvoker;
import util.extension.ExtensionResult;

/**
 * 微信企业号统一响应处理接口.
 */
public class WxCpAPI extends Controller {

    /**
     * 响应微信心跳检查.
     *
     * @param msg_signature
     * @param timestamp
     * @param nonce
     * @param echostr
     */
    public static void heartbeat(String appType,
                                 String msg_signature, String timestamp, String nonce, String echostr) {
        MDC.put("ttid", RandomNumberUtil.generateRandomChars(8));
        Logger.info("LOG00001: heartbeat: appType=%s, signature=%s, timestamp=%s, nonce=%s, echostr=%s",
                appType, msg_signature, timestamp, nonce, echostr);

        WxCpConfigStorage wxCpConfigStorage = WeixinCpHelper.getWxCpConfigStorage(appType);
        if (wxCpConfigStorage == null) {
            Logger.info("LOG00002: 找不到" + appType + "对应的WxCpConfigStorage");
            renderText("不存在的应用信息");
            return;
        }

        WxCpService wxCpService = WeixinCpHelper.getWxCpService(wxCpConfigStorage);

        if (StringUtils.isNotBlank(echostr)) {
            if (!wxCpService.checkSignature(msg_signature, timestamp, nonce, echostr)) {
                // 消息签名不正确，说明不是公众平台发过来的消息
                renderText("非法请求");
            }
            WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage);
            Logger.info("onMessage echostr is %s ---", echostr.trim());
            String plainText = cryptUtil.decrypt(echostr.trim());
            // 说明是一个仅仅用来验证的请求，回显echostr
            renderText(plainText);
        }
        renderText("不是回显请求");
    }

    /**
     * 响应企业号回调信息.
     */
    public static void onMessage() {
        //生成日志跟踪ID.
        MDC.put("ttid", RandomNumberUtil.generateRandomChars(8));
        String encryptedXml = IO.readContentAsString(request.body);
        //Logger.info("encryptedXml=%s", encryptedXml);

        String appType = params.get("appType");
        String msg_signature = params.get("msg_signature");
        String timestamp = params.get("timestamp");
        String nonce = params.get("nonce");
        Logger.info("onMessage: appType=%s, signature=%s, timestamp=%s, nonce=%s",
                appType, msg_signature, timestamp, nonce);

        if (StringUtils.isBlank(encryptedXml)) {
            Logger.info("Empty Body XML");
            renderText("Empty XML");
        }
        Logger.info("Body is Not Empty : " + encryptedXml);

        if (appType == null) {
            appType = "WY";
        }
        WxcpAppType enuAppType = EnumUtils.getEnum(WxcpAppType.class, appType.toUpperCase());
        if (enuAppType == null) {
            enuAppType = WxcpAppType.WY;
        }
        WxCpConfigStorage wxCpConfigStorage = WeixinCpHelper.getWxCpConfigStorage(enuAppType);
        Logger.info("wxCpConfigStorage :" + wxCpConfigStorage);
        WxCpService wxCpService = WeixinCpHelper.getWxCpService(wxCpConfigStorage);
        Logger.info("wxCpService :" + wxCpService);
        WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage);
        Logger.info("cryptUtil :" + cryptUtil);
        Logger.info("msg_signature = %s | timestamp = %s | nonce = %s | encryptedXml = %s", msg_signature, timestamp, nonce, encryptedXml);
        String plainText = cryptUtil.decrypt(msg_signature, timestamp, nonce, encryptedXml);
        Logger.info(" plainText=" + plainText);
//
//        WxCpXmlMessage inMessage = WxCpXmlMessage.fromEncryptedXml(encryptedXml,
//                wxCpConfigStorage,
//                timestamp, nonce, msg_signature);
        WxCpXmlMessage inMessage = XStreamTransformer.fromXml(WxCpXmlMessage.class, plainText);
        Logger.info("inMessage=" + inMessage.toString());

//        Logger.info("LA :" + inMessage.toString());
        WxCpContext wxCpContext = WxCpContext.build(enuAppType, wxCpConfigStorage, wxCpService, inMessage);
        ExtensionResult result = ExtensionInvoker.run(WxCpInvocation.class, wxCpContext, new DefaultAction<WxCpContext>() {
            @Override
            public ExtensionResult execute(WxCpContext context) {
                Logger.info("无法识别的操作，返回空串.");
                return ExtensionResult.SUCCESS;
            }
        });

        if (result.isOk()) {
            WxCpXmlOutMessage outMessage = wxCpContext.outMessage;
            if (outMessage != null) {
                String outXml = outMessage.toEncryptedXml(wxCpConfigStorage);
                Logger.info("立即返回消息: original xml:\n"
                        + XStreamTransformer.toXml((Class) outMessage.getClass(), outMessage)
                        + "\n encrypt xml:\n" + outXml
                );
                Logger.info("立即返回消息 fromUser=%s, toUser=%s", outMessage.getFromUserName(), outMessage.getToUserName());
                renderXml(outXml);
            }
        }

        Logger.info("空串表示无响应");

        // 空串表示无响应，当然可能是异步回复
        renderText("");
    }
}
